When I studied computer science for five years there was a lot of mathematics. Equality was probably the simplest part. After ten years of working, I’ve done a lot of JavaScript. Equality is not the simplest part… Why?
false == 0 // true ['1', '2', '3'] == '1,2,3' // true undefined == null // true "wtf" == "WTF" // false
First of all, JavaScript has two operators for equality: ==
and ===
. In order to understand equality, we have to understand the difference between these two options. As we know equality from other programming languages and mathematics, ===
behaves the way we are used to.
So, if you’re able to keep ==
away from the JavaScript-codebase you’ll probably save yourself from unnecessary heart disease. Unfortunately, sooner or later we have to make changes in a codebase where ==
is commonly used - then it’s important to understand the consequences of making changes!
x == y
There are a lot of rules to be aware of when using ==
. Let’s take a walkthrough of these rules and try to understand them by some examples.
1 If x
and y
is the same data type the behavior of ==
is the same as ===
1==1 => 1===1 "abc" == "ABC => "abc" === "ABC" [1,2,3] == [1,2,3] => [1,2,3] === [1,2,3]
This is a rule that can make refactoring ==
to ===
a bit easier. If you expect both values to be the same data type - add another equal sign and breathe!
2 Truthy if x
and y
is undefined
and null
null == undefined // true undefined == null // true null === undefined // false
null
and undefined
are special cases and we have to accept that they are equal when using double-quotes. But I’m not sure if I like it...
3 If x
and y
are the data types number and string - try to convert the string into number and perform ==
'2' == 2 => Number('2') == 2 // true '2.5' == 2.5 => Number('2.5') == 2.5 // true '' == 0 => Number('') == 0 // true 'evil' == 666 => Number('evil') == 666 // false BigInt(2) == "2" -> BigInt(2) == BigInt("2") // true
If one value is a string type and the other is numeric, JavaScript compares the numeric value of the string. Remember, converting an empty string to a number results in 0
.
4 If x
or y
is a boolean type - convert it to a number and perform ==
false == 0 => 0 == 0 // true false == '0' => 0 == '0' => 0 == 0 // true true == 1 => 1 == 1 // true false == '' => 0 == '' => 0 == 0 // true
Boolean values converted to a number type results in 0 (false
) or 1 (true
). Be aware of the second line, after converting false
to 0 the comparison is now a numeric and string data type. Fortunately, you have just learned how this works!
5 If x
and y
is respectively an Object and either String, Number, Bigint or Symbol - convert the Object to primitive and perform ==
['1', '2', '3'] == '1,2,3' => ['1', '2', '3'].toString() === '1,2,3' // true [1,2,3] == '1,2,3' => true const me = { toString() { return "lazy"; }, valueOf() { return "1337" } } const you = { toString() { return "lazy"; }, valueOf() { return { key: "1337" } } } me == "lazy" // false me == "1337" // true me == [1,3,3,7] // false you == "lazy" // true you == {key: "1337"} // false me == BigInt(1337) // true me == 1337 // true
Converting the data type object into primitive is usually done by returning the value of valueOf()
-function. If this is not implemented or does not return a primitive value, then it returns the value of toString()
-function.
6 If x
and y
is BigInt and Number then return true
if the mathematical value is the same
123 == BigInt(123) // true 999 == BigInt(123) // false
7 If none of the above applies, return false
!
[1,2,3] == { valueOf() { return "1,2,3" } } // false since both are objects 0 == null // false 0 == NaN // false 0 == undefined // false null == false // false NaN == false // false undefined == false // false
As mentioned above, avoid using ==
in your JavaScript code. Unless all of the rules above fits in your, and your teammates, head - please use ===
!